package xyz.zcq.zcqrpc.protocol;

import io.vertx.core.buffer.Buffer;
import xyz.zcq.zcqrpc.model.RpcRequest;
import xyz.zcq.zcqrpc.model.RpcResponse;
import xyz.zcq.zcqrpc.serializer.Serializer;
import xyz.zcq.zcqrpc.serializer.SerializerFactory;

import java.io.IOException;

/**
 * 协议消息解码器
 */
public class ProtocolMessageDecoder {

    /**
     * 解码
     *
     * @param buffer 字节数组
     * @return 协议消息
     */
    public static ProtocolMessage<?> decode(Buffer buffer) throws IOException {
        ProtocolMessage.Header header = new ProtocolMessage.Header();

        byte magic = buffer.getByte(0);
        if (ProtocolConstant.PROTOCOL_MAGIC != magic) {
            throw new RuntimeException("消息 magic 非法");
        }
        header.setMagic(magic);
        header.setVersion(buffer.getByte(1));
        header.setSerializer(buffer.getByte(2));
        header.setType(buffer.getByte(3));
        header.setStatus(buffer.getByte(4));
        header.setRequestId(buffer.getLong(5));
        header.setBodyLength(buffer.getInt(13));
        byte[] body = buffer.getBytes(17, 17 + header.getBodyLength());
        ProtocolMessageTypeEnum pmt = ProtocolMessageTypeEnum.getByValue(header.getType());
        if (pmt == null) {
            throw new RuntimeException("序列化消息的类型不存在");
        }
        ProtocolMessageSerializerEnum pms = ProtocolMessageSerializerEnum.getByKey(header.getSerializer());
        if (pms == null) {
            throw new RuntimeException("序列化消息的序列化类型不存在");
        }
        Serializer serializer = SerializerFactory.getInstance(pms.getValue());
        switch (pmt) {
            case REQUEST:
                RpcRequest rpcRequest = serializer.deserialization(body, RpcRequest.class);
                return new ProtocolMessage<>(header, rpcRequest);
            case RESPONSE:
                RpcResponse rpcResponse = serializer.deserialization(body, RpcResponse.class);
                return new ProtocolMessage<>(header, rpcResponse);
            case HEART_BEAT:
            case OTHERS:
            default:
                throw new RuntimeException("暂不支持该消息类型");
        }
    }

}
